class ZeroEvenOdd {
private:
    int n;
    int m_num;
    int flg;
    condition_variable m_cv;
    mutex m_mtx;
public:
    ZeroEvenOdd(int n) {
        this->n = n;
        m_num=1;
        flg=0;
    }

    // printNumber(x) outputs "x", where x is an integer.
    void zero(function<void(int)> printNumber) {

        for(int i=0;i<n;++i){
            unique_lock<mutex> loc(m_mtx);
            m_cv.wait(loc,[this](){
                return flg==0;
            });
            printNumber(0);
            flg=m_num%2==0?2:1;
            m_cv.notify_all();        
        }
    }

    void even(function<void(int)> printNumber) {

        for(int i=2;i<=n;i+=2){
            unique_lock<mutex> loc(m_mtx);
            m_cv.wait(loc,[this](){
                return flg==2;
            });
            printNumber(m_num);
            ++m_num;
            flg=0;
            m_cv.notify_all();        
        }        
    }

    void odd(function<void(int)> printNumber) {

        for(int i=1;i<=n;i+=2){
            unique_lock<mutex> loc(m_mtx);
            m_cv.wait(loc,[this](){
                return flg==1;
            });
            printNumber(m_num);
            ++m_num;
            flg=0;
            m_cv.notify_all();        
        }       
    }
};
